/*-----------------------------------------------------------------------*/
/* Low level disk I/O module skeleton for FatFs     (C)ChaN, 2016        */
/*-----------------------------------------------------------------------*/
/* If a working storage control module is available, it should be        */
/* attached to the FatFs via a glue function rather than modifying it.   */
/* This is an example of glue functions to attach various existing      */
/* storage control modules to the FatFs module with a defined API.       */
/*-----------------------------------------------------------------------*/
#include "rte_rtc.h"
#include "sdio_sdcard.h"
#include "stm32f10x.h"
#include "diskio.h"
#include <time.h>
#include <string.h>

/* 为每个设备定义一个物理编号 */
#define ATA                     0     // SD卡
#define SPI_FLASH               1     // 预留外部SPI Flash使用

#define SD_BLOCKSIZE     512 

extern  SD_CardInfo SDCardInfo;

/*-----------------------------------------------------------------------*/
/* 获取设备状态                                                          */
/*-----------------------------------------------------------------------*/
DSTATUS disk_status(
    BYTE pdrv		/* 物理编号 */
)
{
    DSTATUS status = STA_NOINIT;

    switch (pdrv) {
    case ATA:       /* SD CARD */
        status &= ~STA_NOINIT;
        break;

    case SPI_FLASH:        /* SPI Flash */
        break;

    default:
        status = STA_NOINIT;
    }
    return status;
}

/*-----------------------------------------------------------------------*/
/* 设备初始化                                                            */
/*-----------------------------------------------------------------------*/
DSTATUS disk_initialize(
    BYTE pdrv               /* 物理编号 */
)
{
    DSTATUS status = STA_NOINIT;
    switch (pdrv) {
    case ATA:               /* SD CARD */
        if (SD_Init() == SD_OK)
        {
            status &= ~STA_NOINIT;
        }
        else
        {
            status = STA_NOINIT;
        }
        break;

    case SPI_FLASH:         /* SPI Flash */
        break;

    default:
        status = STA_NOINIT;
    }
    return status;
}


/*-----------------------------------------------------------------------*/
/* 读扇区：读取扇区内容到指定存储区                                              */
/*-----------------------------------------------------------------------*/
DRESULT disk_read(
    BYTE pdrv,      /* 设备物理编号(0..) */
    BYTE* buff,     /* 数据缓存区 */
    DWORD sector,   /* 扇区首地址 */
    UINT count      /* 扇区个数(1..128) */
)
{
    //	DRESULT status = RES_PARERR;
    SD_Error SD_state = SD_OK;

    DRESULT res = RES_OK;
    //	SD_Error Status;

    switch (pdrv) {
    case ATA:	/* SD CARD */
        if (count == 1)
        {
            SD_state = SD_ReadBlock(buff, sector << 9, SD_BLOCKSIZE);
        }
        else
        {
            SD_state = SD_ReadMultiBlocks(buff, sector << 9, SD_BLOCKSIZE, count);
        }

        /* SDIO工作在DMA模式，需要检查操作DMA传输是否完成 */
        SD_state = SD_WaitReadOperation();
        if (SD_state != SD_OK)
        {
            return RES_ERROR;
        }

        //while(SD_GetStatus() != SD_TRANSFER_OK); 如果不插卡，则此处会死机
        {
            uint32_t i;
            SDTransferState status;

            for (i = 0; i < 100000; i++)
            {
                status = SD_GetStatus();
                if (status == SD_TRANSFER_ERROR)
                {
                    res = RES_ERROR;
                    break;
                }
                else if (status == SD_TRANSFER_OK)
                {
                    res = RES_OK;
                    break;
                }
                //  SD_TRANSFER_BUSY 则继续等待 
            }
        }
        break;

    case SPI_FLASH:
        break;

    default:
        res = RES_PARERR;
        break;
    }
    return res;
}



/*-----------------------------------------------------------------------*/
/* 写扇区：见数据写入指定扇区空间上                                      */
/*-----------------------------------------------------------------------*/
#if _USE_WRITE
DRESULT disk_write(
    BYTE pdrv,              /* 设备物理编号(0..) */
    const BYTE* buff,       /* 欲写入数据的缓存区 */
    DWORD sector,           /* 扇区首地址 */
    UINT count              /* 扇区个数(1..128) */
)
{
    DRESULT res = RES_OK;
    SD_Error Status;

    if (!count) {
        return RES_PARERR;      /* Check parameter */
    }

    switch (pdrv) {
    case ATA:                   /* SD CARD */
        if (count == 1)
        {
            Status = SD_WriteBlock((uint8_t*)buff, sector << 9, SD_BLOCKSIZE);
        }
        else
        {
            Status = SD_WriteMultiBlocks((uint8_t*)buff, sector << 9, SD_BLOCKSIZE, count);
        }

        /* SDIO工作在DMA模式，需要检查操作DMA传输是否完成 */
        Status = SD_WaitReadOperation();
        if (Status != SD_OK)
        {
            return RES_ERROR;
        }

        //while(SD_GetStatus() != SD_TRANSFER_OK); 如果不插卡，则此处会死机
        {
            uint32_t i;
            SDTransferState status;

            for (i = 0; i < 100000; i++)
            {
                status = SD_GetStatus();
                if (status == SD_TRANSFER_ERROR)
                {
                    res = RES_ERROR;
                    break;
                }
                else if (status == SD_TRANSFER_OK)
                {
                    res = RES_OK;
                    break;
                }
                //  SD_TRANSFER_BUSY 则继续等待 
            }
        }
        break;

    case SPI_FLASH:
        res = RES_PARERR;
        break;
    }
    return res;
}
#endif


/*-----------------------------------------------------------------------*/
/* 其他控制                                                              */
/*-----------------------------------------------------------------------*/

#if _USE_IOCTL
DRESULT disk_ioctl(
    BYTE pdrv,      /* 物理编号 */
    BYTE cmd,       /* 控制指令 */
    void* buff      /* 写入或者读取数据地址指针 */
)
{
    DRESULT status = RES_PARERR;
    switch (pdrv) {
    case ATA:   /* SD CARD */
        switch (cmd)
        {
            // Get R/W sector size (WORD) 
        case GET_SECTOR_SIZE:
            *(WORD*)buff = SD_BLOCKSIZE;
            break;
            // Get erase block size in unit of sector (DWORD)
        case GET_BLOCK_SIZE:
            *(DWORD*)buff = 1;
            break;

        case GET_SECTOR_COUNT:
            *(DWORD*)buff = SDCardInfo.CardCapacity / SDCardInfo.CardBlockSize;
            break;
        case CTRL_SYNC:
            break;
        }
        status = RES_OK;
        break;

    case SPI_FLASH:
        break;

    default:
        status = RES_PARERR;
    }
    return status;
}
#endif


#if !FF_FS_NORTC && !FF_FS_READONLY
DWORD get_fattime(void)
{
    struct tm rtc;

    /* Get local time */
    if (!rtc_gettime(&rtc)) return 0;

    /* Pack date and time into a DWORD variable */
    return	  ((DWORD)(rtc.tm_year - 1980) << 25)
        | ((DWORD)rtc.tm_mon << 21)
        | ((DWORD)rtc.tm_mday << 16)
        | ((DWORD)rtc.tm_hour << 11)
        | ((DWORD)rtc.tm_min << 5)
        | ((DWORD)rtc.tm_sec >> 1);
}
#endif

